package com.gitee.deament.server.core.cli.db.sortset;

import cn.hutool.core.util.NumberUtil;
import com.gitee.deament.server.config.SystemConfig;
import com.gitee.deament.server.core.annotation.CliHander;
import com.gitee.deament.server.core.cli.AbstractCli;
import com.gitee.deament.server.core.data.ConnectData;
import com.gitee.deament.server.core.data.ZSortSet;
import com.gitee.deament.server.core.data.ZSortSetMember;
import com.gitee.deament.server.core.data.datatype.Value;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.List;

/**
 * ZRANGE key start stop [WITHSCORES]
 * 可用版本： >= 1.2.0
 * 时间复杂度: O(log(N)+M)， N 为有序集的基数，而 M 为结果集的基数。
 * 返回有序集 key 中，指定区间内的成员。
 *
 * 其中成员的位置按 score 值递增(从小到大)来排序。
 *
 * 具有相同 score 值的成员按字典序(lexicographical order )来排列。
 *
 * 如果你需要成员按 score 值递减(从大到小)来排列，请使用 ZREVRANGE key start stop [WITHSCORES] 命令。
 *
 * 下标参数 start 和 stop 都以 0 为底，也就是说，以 0 表示有序集第一个成员，以 1 表示有序集第二个成员，以此类推。 你也可以使用负数下标，以 -1 表示最后一个成员， -2 表示倒数第二个成员，以此类推。
 *
 * 超出范围的下标并不会引起错误。 比如说，当 start 的值比有序集的最大下标还要大，或是 start > stop 时， ZRANGE 命令只是简单地返回一个空列表。 另一方面，假如 stop 参数的值比有序集的最大下标还要大，那么 Redis 将 stop 当作最大下标来处理。
 *
 * 可以通过使用 WITHSCORES 选项，来让成员和它的 score 值一并返回，返回列表以 value1,score1, ..., valueN,scoreN 的格式表示。 客户端库可能会返回一些更复杂的数据类型，比如数组、元组等。
 *
 * 返回值
 * 指定区间内，带有 score 值(可选)的有序集成员的列表。
 * @author deament
 */
@CliHander(command = "ZRANGE")
public class ZRANGEcli extends AbstractCli {
    @Override
    public void executeCli(ChannelHandlerContext channelHandlerContext, String command) {
        List<String> cliValues = getValues(command);
        if (cliValues.size() !=4||cliValues.size() !=5) {
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR wrong number of arguments for 'ZRANGE' command"));
            return;
        }
        if(cliValues.size()==5 && cliValues.get(4).equalsIgnoreCase("WITHSCORES")){
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR wrong number of arguments for 'ZRANGE' command"));
            return;
        }

        String key = cliValues.get(1);
        String start = cliValues.get(2);
        String stop = cliValues.get(3);
        if(!NumberUtil.isInteger(start)|| !NumberUtil.isInteger(stop)){
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("参数错误"));
            return;
        }

        //是否带score输出
        boolean withScores=cliValues.size()==5;
        int db = ConnectData.SELECT_DB_STORAGE.getUseDB(channelHandlerContext.channel().id().asLongText());
        try {
            Value<ZSortSet> zSortSetData = SystemConfig.dbData.getZSortSetData(db, key);
            if(zSortSetData==null ||zSortSetData.getValue()==null ||zSortSetData.getValue().getData()==null){
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(""));
                return;
            }
            int size=zSortSetData.getValue().getData().size();
            //计算正整数且再边界内的start and stop
            int startIndex=  Integer.parseInt(start);
            if(startIndex<0){
                startIndex=size-Math.abs(startIndex)+1;
                if(startIndex<0){
                    channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(""));
                    return;
                }
            }
            if(startIndex>size){
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(""));
                return;
            }

            int stopIndex=  Integer.parseInt(stop);
            if(stopIndex<0){
                stopIndex=size-Math.abs(stopIndex)+1;
                if(stopIndex<0){
                    channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(""));
                    return;
                }
            }
            if(stopIndex>size){
                stopIndex=size;
            }
            if(startIndex>stopIndex){
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(""));
                return;
            }
            StringBuilder msg= new StringBuilder();
            List<ZSortSetMember> zSortSetMembers = zSortSetData.getValue().getData().subList(startIndex, startIndex);
            for (ZSortSetMember zSortSetMember : zSortSetMembers) {
                msg.append(zSortSetMember.getMember()+"\r\n");
                if(withScores){
                    msg.append(zSortSetMember.getScore()+"\r\n");
                }

            }
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame());
            return;

        }catch (Exception e){
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(e.getMessage()));
            return;
        }
    }


}
